# cython: language_level=3
# cython: boundscheck=False
# cython: wraparound=False
# cython: cdivision=True
# cython: nonecheck=False

import numpy as np
cimport numpy as cnp
cimport cython
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t, int64_t
from libc.string cimport memcmp, memcpy
from libc.stdlib cimport malloc, free
from cython.parallel import prange

# 声明NumPy数组类型
ctypedef cnp.uint8_t DTYPE_t

# 差异结构体，用于高效存储比对结果
cdef struct ByteDifference:
    int32_t position
    uint8_t value1
    uint8_t value2
    uint8_t diff_bits

@cython.boundscheck(False)
@cython.wraparound(False)
cdef class CythonFrameComparer:
    """高性能帧比对器
    
    使用Cython优化的核心比对算法，提供C级别的性能
    """
    
    cdef int max_diff_reports
    cdef bint use_parallel
    
    def __init__(self, int max_diff_reports = 100, bint use_parallel = True):
        self.max_diff_reports = max_diff_reports
        self.use_parallel = use_parallel
    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    cdef inline int compare_bytes_fast(self, 
                                      const uint8_t[:] data1,
                                      const uint8_t[:] data2,
                                      ByteDifference* differences,
                                      int max_diffs) nogil:
        """C级别的字节比对函数
        
        Args:
            data1: 第一个数据数组
            data2: 第二个数据数组
            differences: 差异结果缓冲区
            max_diffs: 最大差异报告数量
            
        Returns:
            int: 实际找到的差异数量
        """
        cdef int len1 = data1.shape[0]
        cdef int len2 = data2.shape[0]
        cdef int min_len = len1 if len1 < len2 else len2
        cdef int diff_count = 0
        cdef int i
        cdef uint8_t b1, b2, diff_bits
        
        # 长度不匹配
        if len1 != len2:
            return -1
        
        # 逐字节比对
        for i in range(min_len):
            b1 = data1[i]
            b2 = data2[i]
            
            if b1 != b2:
                if diff_count < max_diffs:
                    differences[diff_count].position = i
                    differences[diff_count].value1 = b1
                    differences[diff_count].value2 = b2
                    differences[diff_count].diff_bits = b1 ^ b2
                
                diff_count += 1
                
                # 超过最大报告数量，但继续计数
                if diff_count >= max_diffs:
                    break
        
        return diff_count
    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    cdef inline bint are_payloads_equal_fast(self,
                                            const uint8_t[:] data1,
                                            const uint8_t[:] data2) nogil:
        """快速判断两个payload是否相等
        
        Args:
            data1: 第一个数据数组
            data2: 第二个数据数组
            
        Returns:
            bint: True表示相等，False表示不相等
        """
        cdef int len1 = data1.shape[0]
        cdef int len2 = data2.shape[0]
        cdef int i
        
        if len1 != len2:
            return False
        
        # 使用memcmp进行快速比较
        if len1 > 0:
            return memcmp(&data1[0], &data2[0], len1) == 0
        
        return True
    
    def compare_payloads_detailed(self,
                                cnp.ndarray[DTYPE_t, ndim=1] payload1,
                                cnp.ndarray[DTYPE_t, ndim=1] payload2,
                                tuple compare_range = None):
        """详细比对两个payload
        
        Args:
            payload1: 第一个payload数据
            payload2: 第二个payload数据
            compare_range: 比对范围 (start, end)
            
        Returns:
            dict: 比对结果
        """
        # 应用比对范围
        cdef cnp.ndarray[DTYPE_t, ndim=1] data1, data2
        cdef const uint8_t[:] data1_view
        cdef const uint8_t[:] data2_view
        cdef int max_diffs
        cdef ByteDifference* differences
        cdef int diff_count
        cdef int actual_reports
        cdef int i
        cdef int actual_position
        
        if compare_range is not None:
            start, end = compare_range
            data1 = payload1[start:end+1]
            data2 = payload2[start:end+1]
        else:
            data1 = payload1
            data2 = payload2
        
        data1_view = data1
        data2_view = data2
        
        # 长度检查
        if data1.shape[0] != data2.shape[0]:
            return {
                'type': 'length_mismatch',
                'length1': data1.shape[0],
                'length2': data2.shape[0]
            }
        
        # 快速相等性检查
        if self.are_payloads_equal_fast(data1_view, data2_view):
            return {'type': 'matching'}
        
        # 详细差异分析
        max_diffs = self.max_diff_reports
        differences = <ByteDifference*>malloc(
            max_diffs * sizeof(ByteDifference))
        
        if not differences:
            return {'type': 'error', 'message': 'Memory allocation failed'}

        try:
            diff_count = self.compare_bytes_fast(
                data1_view, data2_view, differences, max_diffs)
            
            if diff_count == 0:
                return {'type': 'matching'}
            
            # 构建差异列表
            diff_list = []
            actual_reports = min(diff_count, max_diffs)
            
            for i in range(actual_reports):
                actual_position = differences[i].position
                if compare_range is not None:
                    actual_position += compare_range[0]
                
                diff_list.append({
                    'byte_position': actual_position,
                    'value1': int(differences[i].value1),
                    'value2': int(differences[i].value2),
                    'diff_bits': bin(differences[i].diff_bits)[2:].zfill(8)
                })
            
            result = {
                'type': 'content_mismatch',
                'total_differences': diff_count,
                'reported_differences': actual_reports,
                'differences': diff_list
            }
            
            if diff_count > max_diffs:
                result['truncated'] = True
                result['max_reports'] = max_diffs
            
            return result
            
        finally:
            free(differences)
    
    @cython.boundscheck(False)
    @cython.wraparound(False) 
    def batch_compare_payloads(self,
                              list payloads1,
                              list payloads2,
                              tuple compare_range = None):
        """批量比对payload数据
        
        Args:
            payloads1: 第一组payload列表
            payloads2: 第二组payload列表  
            compare_range: 比对范围
            
        Returns:
            list: 比对结果列表，每个元素为bool值（True表示匹配）
        """
        cdef int num_pairs = len(payloads1)
        if len(payloads2) != num_pairs:
            raise ValueError("两个payload列表长度不一致")
        
        cdef list results = []
        cdef cnp.ndarray[DTYPE_t, ndim=1] p1, p2
        cdef cnp.ndarray[DTYPE_t, ndim=1] data1, data2
        cdef const uint8_t[:] data1_view, data2_view
        cdef int i
        
        for i in range(num_pairs):
            # 转换为NumPy数组
            if isinstance(payloads1[i], bytes):
                p1 = np.frombuffer(payloads1[i], dtype=np.uint8)
            else:
                p1 = np.asarray(payloads1[i], dtype=np.uint8)
                
            if isinstance(payloads2[i], bytes):
                p2 = np.frombuffer(payloads2[i], dtype=np.uint8)
            else:
                p2 = np.asarray(payloads2[i], dtype=np.uint8)
            
            # 应用比对范围
            if compare_range is not None:
                start, end = compare_range
                data1 = p1[start:end+1]
                data2 = p2[start:end+1]
            else:
                data1 = p1
                data2 = p2
            
            data1_view = data1
            data2_view = data2
            
            # 快速比对
            is_equal = self.are_payloads_equal_fast(data1_view, data2_view)
            results.append(is_equal)
        
        return results
    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    def parallel_batch_compare(self,
                              cnp.ndarray[DTYPE_t, ndim=2] data_matrix1,
                              cnp.ndarray[DTYPE_t, ndim=2] data_matrix2):
        """并行批量比对（用于大规模数据）
        
        Args:
            data_matrix1: 第一组数据矩阵 (num_frames, frame_size)
            data_matrix2: 第二组数据矩阵 (num_frames, frame_size)
            
        Returns:
            numpy.ndarray: 比对结果数组（bool）
        """
        cdef int num_frames = data_matrix1.shape[0]
        cdef int frame_size = data_matrix1.shape[1]
        
        if data_matrix2.shape[0] != num_frames or data_matrix2.shape[1] != frame_size:
            raise ValueError("数据矩阵形状不匹配")
        
        cdef cnp.ndarray[cnp.uint8_t, ndim=1] results = np.zeros(num_frames, dtype=np.uint8)
        cdef int i
        
        # 并行比对
        if self.use_parallel:
            for i in prange(num_frames, nogil=True):
                results[i] = memcmp(&data_matrix1[i, 0], &data_matrix2[i, 0], frame_size) == 0
        else:
            for i in range(num_frames):
                results[i] = memcmp(&data_matrix1[i, 0], &data_matrix2[i, 0], frame_size) == 0
        
        return results.astype(bool)

@cython.boundscheck(False)
@cython.wraparound(False)
def fast_find_differences(cnp.ndarray[DTYPE_t, ndim=1] data1,
                         cnp.ndarray[DTYPE_t, ndim=1] data2,
                         int max_diffs = 100):
    """快速查找两个数组的差异
    
    Args:
        data1: 第一个数组
        data2: 第二个数组
        max_diffs: 最大差异报告数量
        
    Returns:
        tuple: (差异总数, 差异详情列表)
    """
    cdef const uint8_t[:] data1_view = data1
    cdef const uint8_t[:] data2_view = data2
    cdef int len1 = data1.shape[0]
    cdef int len2 = data2.shape[0]
    cdef ByteDifference* differences
    cdef CythonFrameComparer comparer
    cdef int diff_count
    cdef int actual_reports
    cdef int i
    
    if len1 != len2:
        return -1, [{'type': 'length_mismatch', 'length1': len1, 'length2': len2}]
    
    differences = <ByteDifference*>malloc(
        max_diffs * sizeof(ByteDifference))
    
    if not differences:
        return -1, [{'type': 'error', 'message': 'Memory allocation failed'}]
    
    try:
        comparer = CythonFrameComparer(max_diffs, False)
        diff_count = comparer.compare_bytes_fast(
            data1_view, data2_view, differences, max_diffs)
        
        if diff_count == 0:
            return 0, []
        
        # 构建差异列表
        diff_list = []
        actual_reports = min(diff_count, max_diffs)
        
        for i in range(actual_reports):
            diff_list.append({
                'byte_position': differences[i].position,
                'value1': int(differences[i].value1),
                'value2': int(differences[i].value2),
                'diff_bits': bin(differences[i].diff_bits)[2:].zfill(8)
            })
        
        return diff_count, diff_list
        
    finally:
        free(differences)

@cython.boundscheck(False)
@cython.wraparound(False)
def vectorized_frame_hash(list frames, str frame_format):
    """向量化计算帧哈希值
    
    Args:
        frames: 帧列表
        frame_format: 帧格式
        
    Returns:
        numpy.ndarray: 哈希值数组
    """
    cdef int num_frames = len(frames)
    cdef cnp.ndarray[cnp.int64_t, ndim=1] hashes = np.empty(num_frames, dtype=np.int64)
    cdef cnp.ndarray[DTYPE_t, ndim=1] payload_arr
    cdef dict frame
    cdef int i, j
    cdef int payload_len
    cdef const uint8_t[:] payload_view
    cdef int64_t hash_value
    
    for i in range(num_frames):
        frame = frames[i]
        payload = frame['payload']
        
        # 转换为NumPy数组
        if isinstance(payload, bytes):
            payload_arr = np.frombuffer(payload, dtype=np.uint8)
        else:
            payload_arr = np.asarray(payload, dtype=np.uint8)
        
        # 限制payload长度
        payload_len = payload_arr.shape[0]
        if frame_format == '1092':
            payload_len = min(payload_len, 1024)
        elif frame_format == '896':
            payload_len = min(payload_len, 896)
        
        payload_view = payload_arr[:payload_len]
        
        # 简单哈希算法（可以根据需要优化）
        hash_value = 0
        for j in range(payload_len):
            hash_value = hash_value * 31 + payload_view[j]
        
        hashes[i] = hash_value
    
    return hashes 